feat: Add optional support for per-context summary events.#135
feat: Add optional support for per-context summary events.#135kinyoklion merged 5 commits intomainfrom
Conversation
|
bugbot review |
| EventSummarizer summarizer = summarizersByContext.get(context); | ||
| if (summarizer == null) { | ||
| summarizer = new EventSummarizer(context); | ||
| summarizersByContext.put(context, summarizer); |
There was a problem hiding this comment.
Using LDContext as HashMap key causes incorrect grouping
Medium Severity
PerContextEventSummarizer uses LDContext as a HashMap key, but LDContext.equals()/hashCode() compare all attributes (name, anonymous, custom attributes, private attributes), not just identity (kind + key). Two contexts representing the same user but with different attribute values would produce separate summaries instead of being grouped together. Additionally, LDContext.hashCode() is explicitly documented as inefficient and "not an anticipated or recommended use case" for map keys. The existing ServerSideEventContextDeduplicator demonstrates the correct pattern: keying by getFullyQualifiedKey().
Additional Locations (1)
There was a problem hiding this comment.
This is describing the correct behavior. We want summaries grouped by their exact context accounting for all attributes.
The performance isn't a concern for this use-case. (Even then the performance of this is actually fine given the number of attributes contexts have in practice.)
| */ | ||
| @Override | ||
| public void restoreTo(List<EventSummarizer.EventSummary> previousSummaries) { | ||
| summarizersByContext.clear(); |
There was a problem hiding this comment.
Is there data in these summarizers that needs to be merged with previousSummaries?
There was a problem hiding this comment.
So the original implementation just re-assigned the event state to the previous state.
Really this clear is somewhat redundant. The way these thread handling works there shouldn't be any events added to the summarizer, because this work, and processing events, are single threaded. So the run loop could be working on this, or it could be processing an event, or so forth.
| @Override | ||
| public void restoreTo(List<EventSummarizer.EventSummary> previousSummaries) { | ||
| summarizersByContext.clear(); | ||
| for (EventSummarizer.EventSummary summary : previousSummaries) { |
There was a problem hiding this comment.
How large may this previousSummaries list be in practice? Seems possible to be hundreds/thousands?
There was a problem hiding this comment.
Its a client-side feature, and this would be tied to the flush interval, so it should be small.
Worth noting I have never seen this feature in any other SDK. Other SDKs just drop the summaries.
Per-context summary events are, in general, not something we could do in a high cardinality context environment.
There was a problem hiding this comment.
It could be large if you have like a rampant identify loop. And unreliable/unavailable networking.
There was a problem hiding this comment.
Actually, being as this is called based on the flush worker not being available, I think it wouldn't really grow. Unless somehow the flush worker setup is broken in another way. Like all of them can become stalled for unbounded time.
🤖 I have created a release *beep* *boop* --- ## [1.8.0](launchdarkly-java-sdk-internal-1.7.0...launchdarkly-java-sdk-internal-1.8.0) (2026-02-12) ### Features * Add optional support for per-context summary events. ([#135](#135)) ([3913d6f](3913d6f)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Release/versioning metadata and changelog updates only; no functional code changes in this diff. > > **Overview** > Prepares the `lib/shared/internal` package release `1.8.0` by updating version metadata in `.release-please-manifest.json` and `lib/shared/internal/gradle.properties`. > > Updates `lib/shared/internal/CHANGELOG.md` with the `1.8.0` entry noting *optional support for per-context summary events*. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 55358e5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>


Note
Medium Risk
Touches core analytics event buffering/flush and JSON output paths; enabling per-context summarization changes payload shape/volume and includes context data in summary events, so regressions could affect event delivery and privacy expectations.
Overview
Adds an optional per-context summarization mode that can emit multiple
summaryevents per flush (one perLDContext) instead of a single aggregated summary.Refactors the event pipeline to use a new
EventSummarizerInterfacewithAggregatedEventSummarizer(backward-compatible default) andPerContextEventSummarizer, extendsEventsConfigurationwith aperContextSummarizationflag, and updatesDefaultEventProcessor/EventOutputFormatterto send/restore a list of summaries and to include serializedcontextin summary output when present. Tests are updated and a comprehensivePerContextEventSummarizerTestis added.Written by Cursor Bugbot for commit 3a0f579. This will update automatically on new commits. Configure here.